#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    pbList = new QList<QPushButton*>();

    pbList->push_back(ui->p1);
    pbList->push_back(ui->p2);
    pbList->push_back(ui->p3);
    pbList->push_back(ui->p4);
    pbList->push_back(ui->p5);
    pbList->push_back(ui->p6);
    pbList->push_back(ui->p7);
    pbList->push_back(ui->p8);
    pbList->push_back(ui->p9);
    pbList->push_back(ui->p10);
    pbList->push_back(ui->p11);
    pbList->push_back(ui->p12);
    pbList->push_back(ui->p13);
    pbList->push_back(ui->p14);
    pbList->push_back(ui->p15);
    pbList->push_back(ui->p16);

    QPushButton * tmp;
    foreach (tmp, *pbList)
    {
        connect(tmp, SIGNAL(clicked()), this, SLOT(pClicked()));
    }

    connect(ui->w2, SIGNAL(textEdited(QString)), this, SLOT(setDirections()));
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(okClicked()));
    connect(ui->slider, SIGNAL(sliderMoved(int)), this, SLOT(sliderMove(int)));

    ui->spinBox->setValue(0);

    steps = new QVector< QVector<int> *>;

    inputCheck = false;
    tableCheck = false;
    stepsCheck = false;

    ui->slider->setEnabled(false);
    ui->l1->setVisible(false);
    ui->l2->setVisible(false);
}

MainWindow::~MainWindow()
{
    delete ui;
}

QVector<int> *MainWindow::getStepValueFromPushButtonList()
{
    QVector<int> * step = new QVector<int>;

    QPushButton * tmp;

    foreach(tmp, *pbList)
    {
        step->push_back(tmp->text().toInt());
    }

    return step;
}

bool MainWindow::testStep(QVector<int> *step)
{
    for(int i = 0; i < step->size(); i++)
    {
        for(int j = i+1; j < step->size(); j++ )
        {
            if(step->at(i) == step->at(j)) return false;
        }
    }
    return true;
}

void MainWindow::makeSteps()
{
    ui->slider->setMaximum(steps->size()-1);
    ui->l1->setText("0");
    ui->l2->setText(QString::number(steps->size()-1));
}

bool MainWindow::swap(QVector<int> *step, directions dir)
{
    int zeroPos;
    for(int i = 0; i < 16; i++)
    {
        if(step->at(i) == 0)
        {
            zeroPos = i;
            break;
        }
    }

    if(dir == LEFT)
    {
        if(zeroPos == 0 || zeroPos == 4 || zeroPos == 8 || zeroPos == 12)
        {
            return false;
        }

        int tmp = step->at(zeroPos - 1);
        (*step)[zeroPos - 1] = 0;
        (*step)[zeroPos] = tmp;
    }

    if(dir == RIGHT)
    {
        if(zeroPos == 3 || zeroPos == 7 || zeroPos == 11 || zeroPos == 15)
        {
            return false;
        }

        int tmp = step->at(zeroPos + 1);
        (*step)[zeroPos + 1] = 0;
        (*step)[zeroPos] = tmp;
    }

    if(dir == UP)
    {
        if(zeroPos <= 3)
        {
            return false;
        }

        int tmp = step->at(zeroPos -4);
        (*step)[zeroPos - 4] = 0;
        (*step)[zeroPos] = tmp;
    }

    if(dir == DOWN)
    {
        if(zeroPos >= 12)
        {
            return false;
        }

        int tmp = step->at(zeroPos + 4);
        (*step)[zeroPos + 4] = 0;
        (*step)[zeroPos] = tmp;
    }

    return true;
}

QVector<int> *MainWindow::copyStep(QVector<int> *step)
{
    return new QVector<int>(*step);
}

void MainWindow::pClicked()
{
    QPushButton * tmp = static_cast<QPushButton*>(sender());
    tmp->setText(QString::number(ui->spinBox->value()));

    if(ui->spinBox->value() < 16)
    {
        ui->spinBox->setValue(ui->spinBox->value()+1);
    }

    if(testStep(getStepValueFromPushButtonList()))
    {
        tableCheck = true;
    }
    else
    {
        tableCheck = false;
    }

    ui->pushButton->setEnabled(inputCheck && tableCheck);
}

void MainWindow::setDirections()
{
    QString source = static_cast<QLineEdit *>(sender())->text();

    if(source.size() == 0)
    {
        inputCheck = false;
        ui->pushButton->setEnabled(inputCheck && tableCheck);
        return;
    }

    path = new QVector<directions>(source.size());

    for(int i = 0; i < source.size(); i++)
    {
        if(source.at(i) == 'L')
        {
            (*path)[i] = LEFT;
        }
        else if(source.at(i) == 'P')
        {
            (*path)[i] = RIGHT;
        }
        else if(source.at(i) == 'G')
        {
            (*path)[i] = UP;
        }
        else if(source.at(i) == 'D')
        {
            (*path)[i] = DOWN;
        }
        else
        {
            inputCheck = false;
            ui->pushButton->setEnabled(inputCheck && tableCheck);
            return;
        }
    }
    inputCheck = true;
    ui->pushButton->setEnabled(inputCheck && tableCheck);
}

void MainWindow::okClicked()
{
    if(ui->slider->value() != 0)
    {
        sliderMove(0);
    }
    steps->clear();

    steps->push_back(getStepValueFromPushButtonList());

    stepsCheck = true;

    for(int i = 0; i < path->size(); i++)
    {
        steps->push_back(copyStep(steps->back()));
        if(!swap(steps->back(), path->at(i)))
        {
            stepsCheck = false;
            break;
        }
    }

    if(stepsCheck)
    {
        makeSteps();

        QPalette plt;
        plt.setColor(QPalette::WindowText, Qt::black);
        ui->label_4->setPalette(plt);

        ui->slider->setEnabled(true);
        ui->l1->setVisible(true);
        ui->l2->setVisible(true);
    }
    else
    {
        QPalette plt;
        plt.setColor(QPalette::WindowText, Qt::red);
        ui->label_4->setPalette(plt);

        ui->slider->setEnabled(false);
        ui->l1->setVisible(false);
        ui->l2->setVisible(false);
    }
}

void MainWindow::sliderMove(int m)
{
    ui->l1->setText(QString::number(m));
    for(int i = 0; i < 16; i++)
    {
        pbList->at(i)->setText(QString::number(steps->at(m)->at(i)));
    }
}
